package com.liuqianfei.markme.helpers;

import com.liuqianfei.markme.common.Utils;
import com.liuqianfei.markme.rules.StateInline;
import com.liuqianfei.util.StringUtil;

public class MarkMeHelper
{
    // Parse link destination
    //
    public static Result parseLinkDestination(String str, int pos, int max)
    {
        char code;
        int start = pos, level, lines = 0;
        Result result = new Result(false, 0, 0, "");
        
        if (str.charAt(pos) == 0x3C /* < */)
        {
            pos++;
            while (pos < max)
            {
                code = str.charAt(pos);
                if (code == 0x0A /* \n */ || Utils.isSpace(code))
                    return result;

                if (code == 0x3E /* > */)
                {
                    result.pos = pos + 1;
                    result.str = Utils.unescapeAll(StringUtil.slice(str, start + 1, pos));
                    result.ok = true;
                    return result;
                }
                if (code == 0x5C /* \ */ && pos + 1 < max)
                {
                    pos += 2;
                    continue;
                }
                pos++;
            }

            // no closing '>'
            return result;
        }
        
        // this should be ... } else { ... branch
        level = 0;
        
        while (pos < max)
        {
            code = str.charAt(pos);

            if (code == 0x20)
                break;

            // ascii control characters
            if (code < 0x20 || code == 0x7F)
                break;

            if (code == 0x5C /* \ */ && pos + 1 < max)
            {
                pos += 2;
                continue;
            }

            if (code == 0x28 /* ( */)
            {
                level++;
                if (level > 1)
                    break;
            }

            if (code == 0x29 /* ) */)
            {
                level--;
                if (level < 0)
                    break;
            }

            pos++;
        }
        
        if (start == pos)
            return result;

        result.str = Utils.unescapeAll(StringUtil.slice(str, start, pos));
        result.lines = lines;
        result.pos = pos;
        result.ok = true;
        
        return result;
    }

    // Parse link label
    //
    // this function assumes that first character ("[") already matches;
    // returns the end of the label
    //
    public static int parseLinkLabel(StateInline state, int start, boolean disableNested)
    {
        int level;
        boolean found = false;
        char marker;
        int prevPos;
        int labelEnd = -1;
        int max = state.getPosMax();
        int oldPos = state.getPos();

        state.pos = start + 1;
        level = 1;

        while (state.pos < max)
        {
            marker = state.src.charAt(state.pos);
            if (marker == 0x5D /* ] */)
            {
                level--;
                if (level == 0)
                {
                    found = true;
                    break;
                }
            }

            prevPos = state.pos;
            state.md.parserInline.skipToken(state);
            if (marker == 0x5B /* [ */)
            {
                if (prevPos == state.pos - 1)
                {
                    // increase level if we find text `[`, which is not a part of any token
                    level++;
                }
                else if (disableNested)
                {
                    state.pos = oldPos;
                    return -1;
                }
            }
        }

        if (found)
            labelEnd = state.pos;

        // restore old state
        state.pos = oldPos;

        return labelEnd;
    }

    // Parse link title
    //
    public static Result parseLinkTitle(String str, int pos, int max)
    {
        char marker, code;
        int start = pos, lines = 0;
        Result result = new Result(false, 0, 0, "");

        if (pos >= max)
            return result;

        marker = str.charAt(pos);
        
        if (marker != 0x22 /* " */ && marker != 0x27 /* ' */ && marker != 0x28 /* ( */)
            return result;

        pos++;
        
        // if opening marker is "(", switch it to closing marker ")"
        if (marker == 0x28)
            marker = 0x29;

        while (pos < max)
        {
            code = str.charAt(pos);
            if (code == marker)
            {
                result.pos = pos + 1;
                result.lines = lines;
                result.str = Utils.unescapeAll(StringUtil.slice(str, start + 1, pos));
                result.ok = true;
                return result;
            }
            else if (code == 0x0A)
            {
                lines++;
            }
            else if (code == 0x5C /* \ */ && pos + 1 < max)
            {
                pos++;
                if (str.charAt(pos) == 0x0A)
                    lines++;
            }
            pos++;
        }
        
        return result;
    }
    
}
